package cn.green.config;

import cn.green.config.exceptions.QTableConfigException;
import cn.green.config.interfaces.QTableConfiguration;
import cn.green.core.components.database.DBRouter;
import cn.green.core.components.database.entity.Database;
import cn.green.core.components.database.source.QDataSource;
import cn.green.core.components.ddao.QDcl;
import cn.green.core.components.ddao.QDdl;
import cn.green.core.components.ddao.QDml;
import cn.green.core.components.ddao.QDql;
import cn.green.core.components.dialect.impls.mysql.dialects.MysqlDclDialect;
import cn.green.core.components.dialect.impls.mysql.dialects.MysqlDdlDialect;
import cn.green.core.components.dialect.impls.mysql.dialects.MysqlDmlDialect;
import cn.green.core.components.dialect.impls.mysql.dialects.MysqlDqlDialect;
import cn.green.core.components.lock.TableLock;
import cn.green.core.excel.QExcel;
import cn.green.core.excel.QExcelLogger;
import cn.green.core.executor.DclExecutor;
import cn.green.core.executor.DdlExecutor;
import cn.green.core.executor.DmlExecutor;
import cn.green.core.executor.DqlExecutor;
import cn.green.core.front.QFront;
import cn.green.core.front.impl.DefaultQFront;
import cn.green.manage.cache.QCache;
import cn.green.manage.curd.QConditionCurd;
import cn.green.manage.curd.QFieldCurd;
import cn.green.manage.curd.QTableCurd;
import cn.green.manage.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Map;

/**
 * @author wang.yishu
 * @version 1.0
 * @className QTableAutoConfiguration
 * @description QTable数据库相关配置类
 * @date 2025/1/13 13:54
 */
@Configuration
public class QTableAutoConfiguration {
    //todo 之后需要新增log日志级别配置

    @Qualifier
    private final QConditionCurd qConditionCurd;
    @Qualifier
    private final QFieldCurd qFieldCurd;
    @Qualifier
    private final QTableCurd qTableCurd;

    @Autowired
    public QTableAutoConfiguration(QConditionCurd qConditionCurd, QFieldCurd qFieldCurd, QTableCurd qTableCurd) {
        this.qConditionCurd = qConditionCurd;
        this.qFieldCurd = qFieldCurd;
        this.qTableCurd = qTableCurd;
    }

    public static final String MASTER_KEY = "master";
    //jdbc mysql
    public static final String JDBC_MYSQL = "jdbc:mysql:";
    //jdbc oracle
    public static final String JDBC_ORACLE = "jdbc:oracle:";
    //jdbc sqlserver
    public static final String JDBC_SQL_SERVER = "jdbc:sqlserver:";

    @Bean
    @ConditionalOnMissingBean(QTableConfiguration.class)
    public QTableConfiguration qTableConfiguration() {
        throw new QTableConfigException("QTable Configuration error: [The instance implements QTableConfiguration is not exists!]");
    }

    private static Database getDatabase(String withoutIp, String url) {
        String databaseSchema = withoutIp.split("\\?")[0];
        Database database = new Database();
        database.setDatabaseName(databaseSchema);
        database.setSchemeName(databaseSchema);
        if (url.startsWith(JDBC_MYSQL)) {
            //mysql数据库
            //database.setDatabaseName();
            database.setDdlDialect(new MysqlDdlDialect());
            database.setDclDialect(new MysqlDclDialect());
            database.setDqlDialect(new MysqlDqlDialect());
            database.setDmlDialect(new MysqlDmlDialect());
        }
//        else if (url.startsWith(JDBC_ORACLE)) {
//            //todo oracle数据库
//        } else if (url.startsWith(JDBC_SQL_SERVER)) {
//            //todo sqlserver数据库
//        } else {
//            //todo 使用用户配置的方言
//        }
        return database;
    }

    @Bean
    @ConditionalOnBean(QDataSource.class)
    public DBRouter ddlDialect(QDataSource datasource) {
        DBRouter dbRouter = new DBRouter();
        Map<String, DataSource> dataSourceMap = datasource.getDataSourceMap();
        dataSourceMap.forEach((key, value) -> {
            try {
                boolean isMaster = false;
                //数据库类型
                String url = dataSourceMap.get(key).getConnection().getMetaData().getURL();
                if (MASTER_KEY.equals(key)) {
                    isMaster = true;
                }
                String withoutJdbcUrl = url.substring(url.indexOf("//") + 2);
                String withoutIp = withoutJdbcUrl.substring(withoutJdbcUrl.indexOf("/") + 1);
                Database database = getDatabase(withoutIp, url);
                if (isMaster) {
                    dbRouter.setMaster(database);
                }
                database.setSourceName(key);
                dbRouter.add(database);
            } catch (SQLException e) {
                System.err.println(e.getMessage());
            }
        });
        //默认为mysql方言
        return dbRouter;
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QExcel.class)
    public QExcel qExcel(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQExcel();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QExcelLogger.class)
    public QExcelLogger qExcelLogger(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.qExcelLogger();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(TableLock.class)
    public TableLock tableLock(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.tableLock();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QDdl.class)
    public QDdl ddl(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQDdl();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QDcl.class)
    public QDcl dcl(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQDcl();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QDml.class)
    public QDml dml(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQDml();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QDql.class)
    public QDql dql(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQDql();
    }

    @Bean
    @ConditionalOnBean(QTableConfiguration.class)
    @ConditionalOnMissingBean(QCache.class)
    public QCache qCache(QTableConfiguration qTableConfiguration) {
        return qTableConfiguration.getQCache();
    }

//    @Bean
//    @ConditionalOnBean(QTableConfiguration.class)
//    @ConditionalOnMissingBean(QFront.class)
//    public QFront qFront(QTableConfiguration qTableConfiguration) {
//        return qTableConfiguration.getQFront();
//    }

    @Bean
    @ConditionalOnBean(value = {QDdl.class, DBRouter.class})
    public DdlExecutor ddlExecutor (QDdl ddl, DBRouter dbRouter) {
        return new DdlExecutor(ddl, dbRouter);
    }

    @Bean
    @ConditionalOnBean(value = {QDdl.class, DBRouter.class})
    public DclExecutor dclExecutor (QDcl dcl, DBRouter dbRouter) {
        return new DclExecutor(dcl, dbRouter);
    }

    @Bean
    @ConditionalOnBean(value = {QDml.class, DBRouter.class, TableLock.class})
    public DmlExecutor dmlExecutor (QDml dml, DBRouter dbRouter, TableLock tableLock) {
        return new DmlExecutor(dml, dbRouter, tableLock);
    }

    @Bean
    @ConditionalOnBean(value = {QDml.class, DBRouter.class, QCache.class})
    public DqlExecutor dqlExecutor (QDql dql, DBRouter dbRouter, QCache qCache) {
        return new DqlExecutor(dql, dbRouter, qCache);
    }

    @Bean
    @ConditionalOnMissingBean(QFront.class)
    @ConditionalOnBean(value = {QCache.class})
    public QFront qFront (QCache qCache) {
        return new DefaultQFront(qCache);
    }

    @Bean
    public QConditionService qConditionService(QCache qCache) {
        return new QConditionService(qConditionCurd, qCache);
    }

    @Bean
    @ConditionalOnBean(DclExecutor.class)
    public QDclService qDclService(DclExecutor dclExecutor) {
        return new QDclService(dclExecutor);
    }

    @Bean
    @ConditionalOnBean(value = {QCache.class, DmlExecutor.class, DBRouter.class})
    public QDmlService qDmlService(QCache qCache, DmlExecutor dmlExecutor, DBRouter dbRouter) {
        return new QDmlService(qCache, dmlExecutor, dbRouter);
    }

    @Bean
    @ConditionalOnBean(value = {QCache.class, DdlExecutor.class,DclExecutor.class, DBRouter.class})
    public QDdlService qDdlService(QCache qCache, DdlExecutor ddlExecutor, DclExecutor dclExecutor, DBRouter dbRouter) {
        return new QDdlService(this.qTableCurd, this.qFieldCurd, qCache, ddlExecutor, dclExecutor, dbRouter);
    }

    @Bean
    @ConditionalOnBean(value = {DqlExecutor.class})
    public QDqlService qDqlService(DqlExecutor dqlExecutor) {
        return new QDqlService(dqlExecutor);
    }
}
